//#include "stdafx.h"
#include<stdio.h>
#include <stdlib.h>
#include <windows.h>

#include "usbLib.h"

//////////////////////////////////////////////////////////////////////////////
// DEVICE SETUP (User configurable)

// Device vendor and product id.
#define MY_VID 0x0e8f
#define MY_PID 0x0022

// Device configuration and interface id.
#define MY_CONFIG 1
#define MY_INTF 0

// Device endpoint(s)
#define EP_IN 0x81
#define EP_OUT 0x01

// Device of bytes to transfer.
#define BUF_SIZE 256

usbDrv::usbDrv()
{

}

bool usbDrv::usbOpen(int vid, int pid)
{
	struct usb_bus *bus;
	struct usb_device *dev;

	usb_init(); /* initialize the library */
	usb_find_busses(); /* find all busses */
	usb_find_devices(); /* find all connected devices */

	for (bus = usb_get_busses(); bus; bus = bus->next)
	{
		for (dev = bus->devices; dev; dev = dev->next)
		{
			//vid = MY_VID, pid = MY_PID
			if ((dev->descriptor.idVendor == vid) && (dev->descriptor.idProduct == pid))
			{
				m_dev = usb_open(dev);
				break;
			}
		}
	}

	if (NULL == m_dev)
	{
		printf("error opening device: \n%s\n", usb_strerror());
		return FALSE;
	}
	printf("success: device %04X:%04X opened\n", vid, pid);

	if (usb_set_configuration(m_dev, MY_CONFIG) < 0)
	{
		printf("error setting config #%d: %s\n", MY_CONFIG, usb_strerror());
		usb_close(m_dev);
		return 0;
	}
	else
	{
		printf("success: set configuration #%d\n", MY_CONFIG);
	}

	if (usb_claim_interface(m_dev, 0) < 0)
	{
		printf("error claiming interface #%d:\n%s\n", MY_INTF, usb_strerror());
		usb_close(m_dev);
		return 0;
	}
	else
	{
		printf("success: claim_interface #%d\n", MY_INTF);
	}

	return TRUE;
}

void usbDrv::usbClose()
{
	if (m_dev)
	{
		usb_close(m_dev);
	}
}

int usbDrv::usbRecv(char *rBuffer, int rLen, int mode)
{
	int ret, currLen;
	ret = usb_control_msg(m_dev, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
		14, /* set/get test */
		1,  /* test type    */
		MY_INTF,  /* interface id */
		rBuffer, 1, 1000);

	currLen = 0;
	do
	{
		if (mode == UNBLOCK)
		{
			ret = transfer_bulk_async(EP_IN, rBuffer, rLen, 5000);
		}
		else
		{
			ret = usb_bulk_read(m_dev, EP_IN, rBuffer, rLen, 5000);
		}
		if (ret > 0) currLen += ret;
	} while (ret > 0);
	return currLen;
}

int usbDrv::usbSend(char *wBuffer, int wLen, int mode)
{
	int ret, currLen;
	ret = usb_control_msg(m_dev, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT,
		14, /* set/get test */
		2,  /* test type    */
		MY_INTF,  /* interface id */
		wBuffer, 1, 1000);

	currLen = 0;
	do
	{
		if (mode == UNBLOCK)
		{
			ret = transfer_bulk_async(EP_OUT, &wBuffer[currLen], wLen, 5000);
		}
		else
		{
			ret = usb_bulk_write(m_dev, EP_OUT, &wBuffer[currLen], wLen, 5000);
		}
		if (ret > 0) currLen += ret;
	} while (ret > 0);
	return currLen;
}

int usbDrv::transfer_bulk_async(int ep, char *bytes, int size, int timeout)
{
	int ret;

	// Each async transfer requires it's own context. A transfer
	// context can be re-used.  When no longer needed they must be
	// freed with usb_free_async().
	//
	void* async_context = NULL;

	// Setup the async transfer.  This only needs to be done once
	// for multiple submit/reaps. (more below)
	//
	ret = usb_bulk_setup_async(m_dev, &async_context, ep);
	if (ret < 0)
	{
		printf("error usb_bulk_setup_async:\n%s\n", usb_strerror());
		goto Done;
	}

	// Submit this transfer.  This function returns immediately and the
	// transfer is on it's way to the device.
	//
	ret = usb_submit_async(async_context, bytes, size);
	if (ret < 0)
	{
		printf("error usb_submit_async:\n%s\n", usb_strerror());
		usb_free_async(&async_context);
		goto Done;
	}

	// Wait for the transfer to complete.  If it doesn't complete in the
	// specified time it is cancelled.  see also usb_reap_async_nocancel().
	//
	ret = usb_reap_async(async_context, timeout);

	// Free the context.
	usb_free_async(&async_context);

Done:
	return ret;
}
